import base64
from datetime import datetime
import getopt
import json
import os
import sys
import time
import traceback
import uuid

import numpy as np
import requests
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.gen
from tornado.options import define, options

from config import get_config
from zalog.log import Logger

sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ocr'))

from ocr.document_images_classification import DocumentImagesClassification


configs = get_config()
logger = Logger(time.strftime('%Y-%m-%d-%H%M.log', time.localtime()))

cur_path = os.path.dirname(__file__)  # current path
g_init = False
ocr_parser = DocumentImagesClassification(cur_path)
g_init = True


def npImage(img):
    return np.fromstring(img, np.uint8)


def get_now_time_ms():
    return int(time.time() * 1000)


def oss_2_base64(oss_path):
    res = requests.get(oss_path)
    if res.status_code == 200:
        return True, base64.encodestring(res.content)
    else:
        return False, None


def build_resp(rst):
    resp = {'success': False, 'message': rst[1]}
    return resp


def build_resp_after_ocr(rst):
    resp = {}
    if rst.success_flag:
        resp["success"] = True
        resp["message"] = ""
        resp["result"] = rst.results
    else:
        resp['success'] = False
        resp['message'] = rst.error_msg
    return resp


def _process_req(req):
    # 1. 参数处理
    image_type = req.get("image_type")
    if not image_type:
        return build_resp((False, "missing param: image_type"))
    if image_type == "base64":
        image_b64 = req.get("image_base64")
        if not image_b64:
            return build_resp((False, "missing param: image_base64"))
        image = base64.b64decode(image_b64)
        npimage = npImage(image)
    else:
        return build_resp((False, "invalid image_type"))

    # 2. 算法计算
    result = ocr_parser.process(npimage)

    return build_resp_after_ocr(result)


# image comes from my frontend page
class postTestHandler(tornado.web.RequestHandler):
    # @tornado.gen.coroutine
    def set_default_headers(self):
        self.set_header('Access-Control-Allow-Origin', '*')
        self.set_header('Access-Control-Allow-Headers', '*')
        self.set_header('Access-Control-Max-Age', 1000)
        # self.set_header('Content-type', 'application/json')
        self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
        self.set_header('Access-Control-Allow-Headers',  # '*')
                        'authorization, Authorization, Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Headers, X-Requested-By, Access-Control-Allow-Methods')

    def post(self):
        self.set_header("Content-Type", "application/json")
        uid = str(uuid.uuid1())
        srv_trace_id = uid
        req_start_time = None
        resp_start_time = get_now_time_ms()
        reserved_info = None

        try:
            req = tornado.escape.json_decode(self.request.body)
        except Exception as e:
            logger.logger.error("traceId: {}, Unexpected Exception Input: {}".format(srv_trace_id, json.dumps(req)))
            logger.logger.error(
                "traceId: {}, Unexpected Exception: {}\n{}".format(srv_trace_id, str(e), traceback.format_exc()))
            self.write(json.dumps(
                {
                    "success": False,
                    "message": "json decode failed",
                    # "reserved_info": reserved_info
                }
            )
            )
            self.finish()
        try:
            res = self.process(req)
            logger.logger.info("response data: {}".format(res))
            self.write(json.dumps(res, ensure_ascii=False))
            self.finish()
        except Exception as e:
            logger.logger.error("traceId: {}, Unexpected Exception Input: {}".format(srv_trace_id, json.dumps(req)))
            logger.logger.error(
                "traceId: {}, Unexpected Exception: {}\n{}".format(srv_trace_id, str(e), traceback.format_exc()))
            self.write(json.dumps(
                {
                    "success": False,
                    "message": "ocr process failed",
                    # "reserved_info": reserved_info
                }
            )
            )
            self.finish()

    def process(self, req):
        return _process_req(req)


# listeing http port. default 8000
define("port", default=8080, help="run on the given port", type=int)
__PAGE__ = os.path.join(cur_path, 'index/')  # storage path for demo page


def run_api():
    # tornado.options.parse_command_line()
    logger.logger.info("configs: {}".format(configs))
    # tornado.options.parse_command_line()
    # app = tornado.web.Application(handlers=[(r"/", IndexHandler)])#create Applicaiton instance
    app = tornado.web.Application(
        handlers=[
            (r"/inference", postTestHandler),
            (r'/(.*)', tornado.web.StaticFileHandler, {'path': __PAGE__})
        ]
    )
    sockets = tornado.netutil.bind_sockets(options.port)

    http_server = tornado.httpserver.HTTPServer(app)
    logger.logger.info("Service started at : {}".format(str(datetime.now())))
    logger.logger.info("Service listened on port: {}".format(options.port))
    http_server.add_sockets(sockets)
    tornado.ioloop.IOLoop.instance().start()


def _sendMsgToQueue(producer, writeTopic, msg, consumer, gMsg):
    producer.poll(0)
    producer.produce(writeTopic, json.dumps(msg).encode("utf-8"),
                     callback=lambda err, msg: consumer.commit(message=gMsg))
    producer.flush()


# main function
def main(argv):
    # cmdline参数读取
    module = ""
    try:
        opts, args = getopt.getopt(argv, "hm:", ["module="])
    except getopt.GetoptError:
        sys.stderr.write("Error: server.py -m <module{api|scheduler}>\n")
        sys.stderr.write("   or: server.py --module=<module{api|scheduler}>\n")
        sys.exit(2)
    for opt, arg in opts:
        if opt == "-h":
            print("Usage: server.py -m <module>")
            print("   or: server.py --module=<module>")
            sys.exit()
        elif opt in ("-m", "--module"):
            module = arg

    if module == "":
        sys.stderr.write("Error: module must specified\n")
        sys.exit(2)
    elif module not in ["api", "scheduler"]:
        sys.stderr.write("Error: module should be 'api' or 'scheduler'\n")
        sys.exit(2)

    # 启动服务
    logger.logger.info("start api service")
    run_api()


if __name__ == "__main__":
    main(sys.argv[1:])
